import axios, {
  type AxiosInstance,
  AxiosError,
  type AxiosRequestConfig,
  type AxiosResponse
} from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/user'
import { getInfo, getToken } from './token';
const whiteList = [
  `api/openid-dict-application/by-client-id`,
  '/connect/token',
  '/connect/logout',
  'account/login',
  'account/registe',
  'account/clear',
  'account/send-code',
  'account/vertify-code',
  'account/reset-password'
]

let isRefreshing = false
let requests: Array<(token: string) => void> = []

// 封装刷新token逻辑
function refreshAccessToken() {
  return getToken(new URLSearchParams({
    grant_type: 'refresh_token',
    refresh_token: localStorage.getItem('refresh_token') || '',
    client_id: import.meta.env.VITE_CLIENT_ID,
    client_secret: import.meta.env.VITE_CLIENT_SECRET
  }))
}

class Request {
  private instance: AxiosInstance

  constructor(config: AxiosRequestConfig) {
    this.instance = axios.create(config)

    this.instance.interceptors.request.use(
      async (config: AxiosRequestConfig) => {
        config.withCredentials = true
        if (whiteList.some((item) => config.url.includes(item))) {
          return config
        }
        const token = localStorage.getItem('token')
        if (token) {
          config.headers['Authorization'] = 'Bearer ' + token
        } else {
          ElMessage({
            message: '没有用户凭证',
            type: 'error',
            duration: 5000
          })
          useUserStore().removeUserInfo();
          window.location.href = '/'
          return Promise.reject('无token')
        }

        if (
          config.method == 'get' &&
          config.params &&
          config.params.maxResultCount == 0
        ) {
          config.params.maxResultCount = import.meta.env.VITE_APP_PAGE_SIZE
        }
        return config
      },
      (error: AxiosError) => Promise.reject(error)
    )

    this.instance.interceptors.response.use(
      (response: AxiosResponse) => response.data,
      async (error: AxiosError & { config: any }) => {
        const { response, config } = error
        // 401未授权：access_token 失效
        if (response && response.status === 401) {
          // 避免白名单刷新死循环
          if (whiteList.some((item) => config.url.includes(item))) {
            window.location.href = '/'
            return Promise.resolve({ data: null, status: 401 }) as any;
          }

          if (!isRefreshing) {
            isRefreshing = true
            return refreshAccessToken()
              .then(async (res) => {
                const { access_token, refresh_token } = res
                if (access_token) {
                  localStorage.setItem('token', access_token)
                  localStorage.setItem('refresh_token', refresh_token)
                  // 刷新成功后需要重新刷新用户信息，因为头像的oss地址需要重新获取
                  const userInfo = await getInfo();
                  useUserStore().addUserInfo(userInfo);
                  isRefreshing = false
                  requests.forEach((cb) => cb(access_token))
                  requests = []
                  // 用新token重试原请求
                  config.headers['Authorization'] = 'Bearer ' + access_token
                  return this.instance(config)
                } else {
                  // 刷新失败，跳转登录
                  ElMessage({
                    message: '请重新登录',
                    type: 'warning',
                    duration: 3000
                  })
                  localStorage.removeItem('token')
                  localStorage.removeItem('refresh_token')
                  useUserStore().removeUserInfo();
                  window.location.href = '/'
                  return Promise.resolve({ data: null, status: 401 }) as any;
                }
              })
              .catch((e) => {
                isRefreshing = false
                if (e.response && e.response.status === 400) {
                  localStorage.removeItem('token')
                  ElMessage({
                    message: '您的会话已过期，请重新登录',
                    type: 'warning',
                    duration: 3000
                  })
                  useUserStore().removeUserInfo();
                  window.location.href = '/'
                  return Promise.resolve({ data: null, status: e.response.status }) as any;
                }
              })
          } else {
            // 正在刷新，将请求加入队列，等刷新完重放
            return new Promise((resolve, reject) => {
              requests.push((token: string) => {
                config.headers['Authorization'] = 'Bearer ' + token
                // 重试请求并正确处理成功和失败情况
                this.instance(config).then(response => {
                  resolve(response)
                }).catch(error => {
                  // 重放请求失败，但token是有效的，不应该清除token和跳转登录
                  // 直接reject错误，让调用方处理具体错误
                  reject(error)
                })
              })
            })
          }
        }

        // 其他错误处理
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const data: any = response?.data || {}
        if (data.error && data.error.details) {
          showErrMessage({ msg: data.error.details.errors })
        } else if (data.error?.message) {
          showErrMessage({ msg: data.error.message })
        }
        return Promise.reject(error)
      }
    )
  }

  // 其他不变 ...
  fetchData<T>(options: AxiosRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        .request<any, T>(options)
        .then((res) => {
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
  get<T>(options: AxiosRequestConfig): Promise<T> {
    return this.fetchData<T>({ ...options, method: 'GET' })
  }
  post<T>(options: AxiosRequestConfig): Promise<T> {
    return this.fetchData({ ...options, method: 'POST' })
  }
  put<T>(options: AxiosRequestConfig): Promise<T> {
    return this.fetchData({ ...options, method: 'PUT' })
  }
  delete<T>(options: AxiosRequestConfig): Promise<T> {
    return this.fetchData({ ...options, method: 'DELETE' })
  }
}

// 显示错误消息
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function showErrMessage(err, type: any = 'error', duration = 5000) {
  ElMessage({
    message: err.msg,
    type: type,
    duration: duration,
    grouping: true
  })
}

export const createService = (
  baseURL: string = import.meta.env.VITE_API_BASE_URL
) => {
  return new Request({
    baseURL,
    timeout: 3000000,
    withCredentials: true
  })
}

// 创建axios实例 进行基本参数配置
const appservice = createService()
export default appservice
export const baseService = createService(import.meta.env.VITE_APP_AUTH_API)
